/****************************************************
	文件：Blackboard.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/3/25 18:50:42
	功能：黑板（包含行为树各个节点之间需要传递的信息）
*****************************************************/

using System.Collections.Generic;
using UnityEngine;

namespace HTFW.AI.BehaviorTree
{
    public class Blackboard
    {
        /*
         * 此处拆分多种类型来处理：目的是减少类型转换消耗
         */

        /// <summary>
        /// 缓存所有 int 黑板数据项
        /// </summary>
        Dictionary<BlackboardKey, BlackboardItem<int>> mIntItems;

        /// <summary>
        /// 缓存所有 float 黑板数据项
        /// </summary>
        Dictionary<BlackboardKey, BlackboardItem<float>> mFloatItems;

        /// <summary>
        /// 缓存所有 bool 黑板数据项
        /// </summary>
        Dictionary<BlackboardKey, BlackboardItem<bool>> mBoolItems;

        /// <summary>
        /// 缓存所有 object 黑板数据项
        /// </summary>
        Dictionary<BlackboardKey, BlackboardItem<Vector3>> mVec3Items;

        /// <summary>
        /// 缓存所有 object 黑板数据项
        /// </summary>
        Dictionary<BlackboardKey, BlackboardItem<object>> mObjectItems;

        //todo toadd 更多类型黑板数据


        public Blackboard()
        {
            mIntItems = new Dictionary<BlackboardKey, BlackboardItem<int>>();
            mFloatItems = new Dictionary<BlackboardKey, BlackboardItem<float>>();
            mBoolItems = new Dictionary<BlackboardKey, BlackboardItem<bool>>();
            mVec3Items = new Dictionary<BlackboardKey, BlackboardItem<Vector3>>();
            mObjectItems = new Dictionary<BlackboardKey, BlackboardItem<object>>();
        }


        //------------------------------ Set Value ------------------------------//

        #region Set Value

        /// <summary>
        /// 设置黑板数据 int ，若设置了有效时间，则有效时间到了之后数据将失效
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param 有效时间="validTime"></param>
        public void SetValueInt(BlackboardKey key, int value, float validTime = -1.0f)
        {
            if (mIntItems.TryGetValue(key, out var item) == false)
            {
                item = new BlackboardItem<int>();
                mIntItems.Add(key, item);
            }

            item.SetValue(value, validTime);
        }

        /// <summary>
        /// 设置黑板数据 float ，若设置了有效时间，则有效时间到了之后数据将失效
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="validTime"></param>
        public void SetValueFloat(BlackboardKey key, float value, float validTime = -1.0f)
        {
            if (mFloatItems.TryGetValue(key, out var item) == false)
            {
                item = new BlackboardItem<float>();
                mFloatItems.Add(key, item);
            }

            item.SetValue(value, validTime);
        }

        /// <summary>
        /// 设置黑板数据 bool ，若设置了有效时间，则有效时间到了之后数据将失效
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="validTime"></param>
        public void SetValueBool(BlackboardKey key, bool value, float validTime = -1.0f)
        {
            if (mBoolItems.TryGetValue(key, out var item) == false)
            {
                item = new BlackboardItem<bool>();
                mBoolItems.Add(key, item);
            }

            item.SetValue(value, validTime);
        }

        /// <summary>
        /// 设置黑板数据 Vector3 ，若设置了有效时间，则有效时间到了之后数据将失效
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="validTime"></param>
        public void SetValueVec3(BlackboardKey key, Vector3 value, float validTime = -1.0f)
        {
            if (mVec3Items.TryGetValue(key, out var item) == false)
            {
                item = new BlackboardItem<Vector3>();
                mVec3Items.Add(key, item);
            }

            item.SetValue(value, validTime);
        }

        /// <summary>
        /// 设置黑板数据 object，若设置了有效时间，则有效时间到了之后数据将失效
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="validTime"></param>
        public void SetValueObject(BlackboardKey key, object value, float validTime = -1.0f)
        {
            if (mObjectItems.TryGetValue(key, out var item) == false)
            {
                item = new BlackboardItem<object>();
                mObjectItems.Add(key, item);
            }

            item.SetValue(value, validTime);
        }

        #endregion


        //------------------------------ Get Value ------------------------------//

        #region Get Value

        /// <summary>
        /// 获取黑板数据 int
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public int GetValueInt(BlackboardKey key, int defaultValue)
        {
            if (!mIntItems.TryGetValue(key, out var item)) return defaultValue;
            return item.GetValue(defaultValue);
        }

        /// <summary>
        /// 获取黑板数据 float
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public float GetValueFloat(BlackboardKey key, float defaultValue)
        {
            if (!mFloatItems.TryGetValue(key, out var item)) return defaultValue;
            return item.GetValue(defaultValue);
        }

        /// <summary>
        /// 获取黑板数据 bool
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public bool GetValueBool(BlackboardKey key, bool defaultValue)
        {
            if (!mBoolItems.TryGetValue(key, out var item)) return defaultValue;
            return item.GetValue(defaultValue);
        }

        /// <summary>
        /// 获取黑板数据 Vector3
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public Vector3 GetValueVec3(BlackboardKey key, Vector3 defaultValue)
        {
            if (!mVec3Items.TryGetValue(key, out var item)) return defaultValue;
            return item.GetValue(defaultValue);
        }

        /// <summary>
        /// 获取黑板数据 object
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetValueObject<T>(BlackboardKey key, T defaultValue)
        {
            if (!mObjectItems.TryGetValue(key, out var item)) return defaultValue;
            return (T) item.GetValue(defaultValue);
        }

        #endregion


        //------------------------------ Delete Value ------------------------------//

        #region Delete Value

        /// <summary>
        /// 删除黑板数据 int
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteValueInt(BlackboardKey key)
        {
            return mIntItems.Remove(key);
        }

        /// <summary>
        /// 删除黑板数据 float
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteValueFloat(BlackboardKey key)
        {
            return mFloatItems.Remove(key);
        }

        /// <summary>
        /// 删除黑板数据 bool
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteValueBool(BlackboardKey key)
        {
            return mBoolItems.Remove(key);
        }

        /// <summary>
        /// 删除黑板数据 Vector3
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteValueVec3(BlackboardKey key)
        {
            return mVec3Items.Remove(key);
        }

        /// <summary>
        /// 删除黑板数据 object
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteValueObject(BlackboardKey key)
        {
            return mObjectItems.Remove(key);
        }

        #endregion


        //------------------------------ Contain Value ------------------------------//

        #region Contain Value

        /// <summary>
        /// 黑板中是否包含指定 int 数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsValueInt(BlackboardKey key)
        {
            if (!mIntItems.ContainsKey(key)) return false;
            return mIntItems[key].ValidValue();
        }

        /// <summary>
        /// 黑板中是否包含指定 float 数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsValueFloat(BlackboardKey key)
        {
            if (!mFloatItems.ContainsKey(key)) return false;
            return mFloatItems[key].ValidValue();
        }

        /// <summary>
        /// 黑板中是否包含指定 bool 数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsValueBool(BlackboardKey key)
        {
            if (!mBoolItems.ContainsKey(key)) return false;
            return mBoolItems[key].ValidValue();
        }

        /// <summary>
        /// 黑板中是否包含指定 Vector3 数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsValueVec3(BlackboardKey key)
        {
            if (!mVec3Items.ContainsKey(key)) return false;
            return mVec3Items[key].ValidValue();
        }

        /// <summary>
        /// 黑板中是否包含指定 object 数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsValueObject(BlackboardKey key)
        {
            if (!mObjectItems.ContainsKey(key)) return false;
            return mObjectItems[key].ValidValue();
        }

        #endregion


        //------------------------------ TryGet Value ------------------------------//

        #region TryGet Value

        /// <summary>
        /// 尝试从黑板中获取指定 int 数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValueInt(BlackboardKey key, out int value)
        {
            if (!mIntItems.TryGetValue(key, out var item)
                || !item.ValidValue())
            {
                value = default;
                return false;
            }

            value = item.GetValue(default);
            return true;
        }

        /// <summary>
        /// 尝试从黑板中获取指定 float 数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValueFloat(BlackboardKey key, out float value)
        {
            if (!mFloatItems.TryGetValue(key, out var item)
                || !item.ValidValue())
            {
                value = default;
                return false;
            }

            value = item.GetValue(default);
            return true;
        }

        /// <summary>
        /// 尝试从黑板中获取指定 bool 数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValueBool(BlackboardKey key, out bool value)
        {
            if (!mBoolItems.TryGetValue(key, out var item)
                || !item.ValidValue())
            {
                value = default;
                return false;
            }

            value = item.GetValue(default);
            return true;
        }

        /// <summary>
        /// 尝试从黑板中获取指定 Vector3 数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValueVec3(BlackboardKey key, out Vector3 value)
        {
            if (!mVec3Items.TryGetValue(key, out var item)
                || !item.ValidValue())
            {
                value = default;
                return false;
            }

            value = item.GetValue(default);
            return true;
        }

        /// <summary>
        /// 尝试从黑板中获取指定 object 数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public bool TryGetValueObject<T>(BlackboardKey key, out T value)
        {
            if (!mObjectItems.TryGetValue(key, out var item)
                || !item.ValidValue())
            {
                value = default(T);
                return false;
            }

            value = (T) item.GetValue(default(T));
            return true;
        }

        #endregion
    }
}